﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;

namespace Shine.Util.Security
{
    /// <summary>
    /// 加密服务
    /// </summary>
    public class SecurityHelper
    {
        /// <summary>
        /// 单向加密
        /// </summary>
        /// <param name="str">需要被加密的字符串</param>
        /// <param name="key">加密方式，只能是MD5或者SHA1</param>
        /// <returns></returns>
        public static string EnCryptUnidirectional(string str, string key)
        {
            if (string.IsNullOrWhiteSpace(key)) return str;
            if (key.ToUpper() != "MD5" && key.ToUpper() != "SHA1") return str;
            return System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(str, key.ToUpper());
        }
        
        /// <summary>
        /// 使用RSACryptoServiceProvider进行加密，加密后的结果有特殊字符
        /// </summary>
        /// <param name="str"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public static string EnCryptRSA(string str, string key)
        {
            if (String.IsNullOrWhiteSpace(key)) return str;
            CspParameters param = new CspParameters();
            param.KeyContainerName = key;//密匙容器的名称，保持加密解密一致才能解密成功
            using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(param))
            {
                byte[] plaindata = Encoding.Default.GetBytes(str);//将要加密的字符串转换为字节数组
                byte[] encryptdata = rsa.Encrypt(plaindata, false);//将加密后的字节数据转换为新的加密字节数组
                return Convert.ToBase64String(encryptdata);//将加密后的字节数组转换为字符串
            }
        }

        /// <summary>
        /// 对应EnCryptRSA进行解密
        /// </summary>
        /// <param name="str"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public static string DeCryptRSA(string str, string key)
        {
            if (String.IsNullOrWhiteSpace(key)) return str; 
            CspParameters param = new CspParameters();
            param.KeyContainerName = key;//密匙容器的名称，保持加密解密一致才能解密成功
            using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(param))
            {
                byte[] encryptdata = Convert.FromBase64String(str);
                byte[] decryptdata = rsa.Decrypt(encryptdata, false);
                return Encoding.Default.GetString(decryptdata);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        private static byte[] desKeys = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF };
        
        /// <summary>
        /// 使用DESCryptoServiceProvider进行加密，需要密钥
        /// </summary>
        /// <param name="value">待加密的字符串</param>
        /// <param name="key">加密密钥,要求为8位</param>
        /// <returns>加密成功返回加密后的字符串，失败返回源串</returns>
        public static string EnCryptDES(string value, string key)
        {
            try
            {
                key = key.PadRight(8, '0');
                byte[] rgbKey = Encoding.UTF8.GetBytes(key.Substring(0, 8));
                byte[] rgbIV = desKeys;
                byte[] inputByteArray = Encoding.UTF8.GetBytes(value);
                DESCryptoServiceProvider dCSP = new DESCryptoServiceProvider();
                MemoryStream mStream = new MemoryStream();
                CryptoStream cStream = new CryptoStream(mStream, dCSP.CreateEncryptor(rgbKey, rgbIV), CryptoStreamMode.Write);
                cStream.Write(inputByteArray, 0, inputByteArray.Length);
                cStream.FlushFinalBlock();
                return Convert.ToBase64String(mStream.ToArray());
            }
            catch
            {
                return value;
            }
        }

        /// <summary>
        /// 对应DESCryptoServiceProvider进行解密 
        /// </summary>
        /// <param name="value">待解密的字符串</param>
        /// <param name="key">解密密钥,要求为8位,和加密密钥相同</param>
        /// <returns>解密成功返回解密后的字符串，失败返源串</returns>
        public static string DeCryptDES(string value, string key)
        {
            try
            {
                key = key.PadRight(8, '0');
                byte[] rgbKey = Encoding.UTF8.GetBytes(key);
                byte[] rgbIV = desKeys;
                byte[] inputByteArray = Convert.FromBase64String(value);
                DESCryptoServiceProvider DCSP = new DESCryptoServiceProvider();
                MemoryStream mStream = new MemoryStream();
                CryptoStream cStream = new CryptoStream(mStream, DCSP.CreateDecryptor(rgbKey, rgbIV), CryptoStreamMode.Write);
                cStream.Write(inputByteArray, 0, inputByteArray.Length);
                cStream.FlushFinalBlock();
                return Encoding.UTF8.GetString(mStream.ToArray());
            }
            catch
            {
                return value;
            }

        }
        
        /// <summary>
        /// 使用DESCryptoServiceProvider进行加密，需要密钥。扩展过随机字符
        /// </summary>
        /// <param name="value">待加密的字符串</param>
        /// <param name="key">密钥(最大长度8)</param>
        /// <returns>加密后的字符串</returns>
        public static string EnCryptDES2(string value, string key)
        {
            key = key.PadRight(8, '0');
            SymmetricAlgorithm sa = new DESCryptoServiceProvider();
            sa.Key = Encoding.UTF8.GetBytes(key.Substring(0, 8));
            sa.IV = desKeys;
            ICryptoTransform ict = sa.CreateEncryptor();
            byte[] byt = Encoding.UTF8.GetBytes(value);
            MemoryStream ms = new MemoryStream();
            CryptoStream cs = new CryptoStream(ms, ict, CryptoStreamMode.Write);
            cs.Write(byt, 0, byt.Length);
            cs.FlushFinalBlock();
            cs.Close();
            //加上一些干扰字符
            string retVal = Convert.ToBase64String(ms.ToArray());
            System.Random ra = new Random();
            for (int i = 0; i < 8; i++)
            {
                int radNum = ra.Next(36);
                char radChr = Convert.ToChar(radNum + 65);
                retVal = retVal.Substring(0, 2 * i + 1) + radChr.ToString() + retVal.Substring(2 * i + 1);//生成一个随机字符
            }
            return retVal;
        }
        
        /// <summary>
        /// 相对于EnCryptDES2进行解密
        /// </summary>
        /// <param name="value">待解密的字符串</param>
        /// <param name="key">密钥(最大长度8)</param>
        /// <returns>解密后的字符串</returns>
        public static string DeCryptDES2(string value, string key)
        {
            string tmp = value;//去掉干扰字符
            if (tmp.Length < 16) return "";
            for (int i = 0; i < 8; i++)
            {
                tmp = tmp.Substring(0, i + 1) + tmp.Substring(i + 2);
            }
            value = tmp;
            key = key.PadRight(8, '0');
            SymmetricAlgorithm sa = new DESCryptoServiceProvider();
            sa.Key = Encoding.UTF8.GetBytes(key.Substring(0, 8));
            sa.IV = desKeys;
            ICryptoTransform ict = sa.CreateDecryptor();
            byte[] byt = Convert.FromBase64String(value);
            MemoryStream ms = new MemoryStream();
            CryptoStream cs = new CryptoStream(ms, ict, CryptoStreamMode.Write);
            cs.Write(byt, 0, byt.Length);
            cs.FlushFinalBlock();
            cs.Close();
            return Encoding.UTF8.GetString(ms.ToArray());
        }

    }
}
